Ext.form.TriggerField = Ext.extend(Ext.form.TextField,
{
	defaultAutoCreate:
	{
		tag: "input",
		type: "text",
		size: "16",
		autocomplete: "off"
	},
	hideTrigger: false,
	editable: true,
	readOnly: false,
	wrapFocusClass: 'x-trigger-wrap-focus',
	autoSize: Ext.emptyFn,
	monitorTab: true,
	deferHeight: true,
	mimicing: false,
	actionMode: 'wrap',
	defaultTriggerWidth: 17,

	// private
	onResize: function( w, h )
	{
		Ext.form.TriggerField.superclass.onResize.call(this, w, h);
		var tw = this.getTriggerWidth();
		if( Ext.isNumber(w) )
		{
			this.el.setWidth(w - tw);
		}
		this.wrap.setWidth(this.el.getWidth() + tw);
	},

	getTriggerWidth: function()
	{
		var tw = this.trigger.getWidth();
		if( !this.hideTrigger && !this.readOnly && tw === 0 )
		{
			tw = this.defaultTriggerWidth;
		}
		return tw;
	},

	// private
	alignErrorIcon: function()
	{
		if( this.wrap )
		{
			this.errorIcon.alignTo(this.wrap, 'tl-tr',
			[
			    2, 0
			]);
		}
	},

	// private
	onRender: function( ct, position )
	{
		this.doc = Ext.isIE ? Ext.getBody() : Ext.getDoc();
		Ext.form.TriggerField.superclass.onRender.call(this, ct, position);
		
		this.wrap = this.el.wrap(
		{
			cls: 'x-form-field-wrap x-form-field-trigger-wrap'
		});
		this.trigger = this.wrap.createChild(this.triggerConfig ||
		{
			tag: "img",
			src: Ext.BLANK_IMAGE_URL,
			alt: "",
			cls: "x-form-trigger " + this.triggerClass
		});
		this.initTrigger();
		if( !this.width )
		{
			this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
		}
		this.resizeEl = this.positionEl = this.wrap;
	},

	getWidth: function()
	{
		return (this.el.getWidth() + this.trigger.getWidth());
	},

	updateEditState: function()
	{
		if( this.rendered )
		{
			if( this.readOnly )
			{
				this.el.dom.readOnly = true;
				this.el.addClass('x-trigger-noedit');
				this.mun(this.el, 'click', this.onTriggerClick, this);
				this.trigger.setDisplayed(false);
			}
			else
			{
				if( !this.editable )
				{
					this.el.dom.readOnly = true;
					this.el.addClass('x-trigger-noedit');
					this.mon(this.el, 'click', this.onTriggerClick, this);
				}
				else
				{
					this.el.dom.readOnly = false;
					this.el.removeClass('x-trigger-noedit');
					this.mun(this.el, 'click', this.onTriggerClick, this);
				}
				this.trigger.setDisplayed(!this.hideTrigger);
			}
			this.onResize(this.width || this.wrap.getWidth());
		}
	},

	/**
	 * Changes the hidden status of the trigger.
	 * 
	 * @param {Boolean}
	 *          hideTrigger True to hide the trigger, false to show it.
	 */
	setHideTrigger: function( hideTrigger )
	{
		if( hideTrigger != this.hideTrigger )
		{
			this.hideTrigger = hideTrigger;
			this.updateEditState();
		}
	},

	/**
	 * Allow or prevent the user from directly editing the field text. If false is passed, the user will only be able to modify the field using the trigger. Will
	 * also add a click event to the text field which will call the trigger. This method is the runtime equivalent of setting the {@link #editable} config option
	 * at config time.
	 * 
	 * @param {Boolean}
	 *          value True to allow the user to directly edit the field text.
	 */
	setEditable: function( editable )
	{
		if( editable != this.editable )
		{
			this.editable = editable;
			this.updateEditState();
		}
	},

	/**
	 * Setting this to true will supersede settings {@link #editable} and {@link #hideTrigger}. Setting this to false will defer back to {@link #editable} and
	 * {@link #hideTrigger}. This method is the runtime equivalent of setting the {@link #readOnly} config option at config time.
	 * 
	 * @param {Boolean}
	 *          value True to prevent the user changing the field and explicitly hide the trigger.
	 */
	setReadOnly: function( readOnly )
	{
		if( readOnly != this.readOnly )
		{
			this.readOnly = readOnly;
			this.updateEditState();
		}
	},

	afterRender: function()
	{
		Ext.form.TriggerField.superclass.afterRender.call(this);
		this.updateEditState();
	},

	// private
	initTrigger: function()
	{
		this.mon(this.trigger, 'click', this.onTriggerClick, this,
		{
			preventDefault: true
		});
		this.trigger.addClassOnOver('x-form-trigger-over');
		this.trigger.addClassOnClick('x-form-trigger-click');
	},

	// private
	onDestroy: function()
	{
		Ext.destroy(this.trigger, this.wrap);
		if( this.mimicing )
		{
			this.doc.un('mousedown', this.mimicBlur, this);
		}
		delete this.doc;
		Ext.form.TriggerField.superclass.onDestroy.call(this);
	},

	// private
	onFocus: function()
	{
		Ext.form.TriggerField.superclass.onFocus.call(this);
		if( !this.mimicing )
		{
			this.wrap.addClass(this.wrapFocusClass);
			this.mimicing = true;
			this.doc.on('mousedown', this.mimicBlur, this,
			{
				delay: 10
			});
			if( this.monitorTab )
			{
				this.on('specialkey', this.checkTab, this);
			}
		}
	},

	// private
	checkTab: function( me, e )
	{
		if( e.getKey() == e.TAB )
		{
			this.triggerBlur();
		}
	},

	// private
	onBlur: Ext.emptyFn,

	// private
	mimicBlur: function( e )
	{
		if( !this.isDestroyed && !this.wrap.contains(e.target) && this.validateBlur(e) )
		{
			this.triggerBlur();
		}
	},

	// private
	triggerBlur: function()
	{
		this.mimicing = false;
		this.doc.un('mousedown', this.mimicBlur, this);
		if( this.monitorTab && this.el )
		{
			this.un('specialkey', this.checkTab, this);
		}
		Ext.form.TriggerField.superclass.onBlur.call(this);
		if( this.wrap )
		{
			this.wrap.removeClass(this.wrapFocusClass);
		}
	},

	beforeBlur: Ext.emptyFn,

	// private
	// This should be overriden by any subclass that needs to check whether or not the field can be blurred.
	validateBlur: function( e )
	{
		return true;
	},

	/**
	 * The function that should handle the trigger's click event. This method does nothing by default until overridden by an implementing function. See
	 * Ext.form.ComboBox and Ext.form.DateField for sample implementations.
	 * 
	 * @method
	 * @param {EventObject}
	 *          e
	 */
	onTriggerClick: Ext.emptyFn

	/**
	 * @cfg {Boolean} grow
	 * @hide
	 */
	/**
	 * @cfg {Number} growMin
	 * @hide
	 */
	/**
	 * @cfg {Number} growMax
	 * @hide
	 */
});

/**
 * @class Ext.form.TwinTriggerField
 * @extends Ext.form.TriggerField TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class to be extended by an
 *          implementing class. For an example of implementing this class, see the custom SearchField implementation here: <a
 *          href="http://extjs.com/deploy/ext/examples/form/custom.html">http://extjs.com/deploy/ext/examples/form/custom.html</a>
 */
Ext.form.TwinTriggerField = Ext.extend(Ext.form.TriggerField,
{
	/**
	 * @cfg {Mixed} triggerConfig
	 *      <p>
	 *      A {@link Ext.DomHelper DomHelper} config object specifying the structure of the trigger elements for this Field. (Optional).
	 *      </p>
	 *      <p>
	 *      Specify this when you need a customized element to contain the two trigger elements for this Field. Each trigger element must be marked by the CSS
	 *      class <tt>x-form-trigger</tt> (also see <tt>{@link #trigger1Class}</tt> and <tt>{@link #trigger2Class}</tt>).
	 *      </p>
	 *      <p>
	 *      Note that when using this option, it is the developer's responsibility to ensure correct sizing, positioning and appearance of the triggers.
	 *      </p>
	 */
	/**
	 * @cfg {String} trigger1Class An additional CSS class used to style the trigger button. The trigger will always get the class <tt>'x-form-trigger'</tt> by
	 *      default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
	 */
	/**
	 * @cfg {String} trigger2Class An additional CSS class used to style the trigger button. The trigger will always get the class <tt>'x-form-trigger'</tt> by
	 *      default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
	 */

	initComponent: function()
	{
		Ext.form.TwinTriggerField.superclass.initComponent.call(this);

		this.triggerConfig =
		{
			tag: 'span',
			cls: 'x-form-twin-triggers',
			cn:
			[
			    {
				    tag: "img",
				    src: Ext.BLANK_IMAGE_URL,
				    alt: "",
				    cls: "x-form-trigger " + this.trigger1Class
			    },
			    {
				    tag: "img",
				    src: Ext.BLANK_IMAGE_URL,
				    alt: "",
				    cls: "x-form-trigger " + this.trigger2Class
			    }
			]
		};
	},

	getTrigger: function( index )
	{
		return this.triggers[index];
	},

	afterRender: function()
	{
		Ext.form.TwinTriggerField.superclass.afterRender.call(this);
		var triggers = this.triggers, i = 0, len = triggers.length;

		for( ; i < len; ++i )
		{
			if( this['hideTrigger' + (i + 1)] )
			{
				triggers[i].hide();
			}

		}
	},

	initTrigger: function()
	{
		var ts = this.trigger.select('.x-form-trigger', true), triggerField = this;

		ts.each(function( t, all, index )
		{
			var triggerIndex = 'Trigger' + (index + 1);
			t.hide = function()
			{
				var w = triggerField.wrap.getWidth();
				this.dom.style.display = 'none';
				triggerField.el.setWidth(w - triggerField.trigger.getWidth());
				triggerField['hidden' + triggerIndex] = true;
			};
			t.show = function()
			{
				var w = triggerField.wrap.getWidth();
				this.dom.style.display = '';
				triggerField.el.setWidth(w - triggerField.trigger.getWidth());
				triggerField['hidden' + triggerIndex] = false;
			};
			this.mon(t, 'click', this['on' + triggerIndex + 'Click'], this,
			{
				preventDefault: true
			});
			t.addClassOnOver('x-form-trigger-over');
			t.addClassOnClick('x-form-trigger-click');
		}, this);
		this.triggers = ts.elements;
	},

	getTriggerWidth: function()
	{
		var tw = 0;
		Ext.each(this.triggers, function( t, index )
		{
			var triggerIndex = 'Trigger' + (index + 1), w = t.getWidth();
			if( w === 0 && !this['hidden' + triggerIndex] )
			{
				tw += this.defaultTriggerWidth;
			}
			else
			{
				tw += w;
			}
		}, this);
		return tw;
	},

	// private
	onDestroy: function()
	{
		Ext.destroy(this.triggers);
		Ext.form.TwinTriggerField.superclass.onDestroy.call(this);
	},

	/**
	 * The function that should handle the trigger's click event. This method does nothing by default until overridden by an implementing function. See
	 * {@link Ext.form.TriggerField#onTriggerClick} for additional information.
	 * 
	 * @method
	 * @param {EventObject}
	 *          e
	 */
	onTrigger1Click: Ext.emptyFn,
	/**
	 * The function that should handle the trigger's click event. This method does nothing by default until overridden by an implementing function. See
	 * {@link Ext.form.TriggerField#onTriggerClick} for additional information.
	 * 
	 * @method
	 * @param {EventObject}
	 *          e
	 */
	onTrigger2Click: Ext.emptyFn
});
Ext.reg('trigger', Ext.form.TriggerField);
Ext.reg('twintrigger', Ext.form.TwinTriggerField);
